I'm trying to compile my RPGLE program and I keep getting errors stating that a file i declared at the top is ignored due to no external description. What does this mean? I've been trying to figure it out and still can't come up with a solution. The errors are below the code.
FSHIFTRATESIF E DISK RENAME(SHIFTRATES:SHIFTRATER)
FALLSHIFT IF E K DISK RENAME(ALLSHIFT:ALLSHIFTER)
FCONFIRMPAYCF E WORKSTN
FPAYRPT O E PRINTER OFLIND(*IN01)
DHOURSOVER S 3 0
/FREE
READ SHIFTRATES;
WRITE TITLE;
WRITE COLHDG;
READ ALLSHIFT;
DOW NOT %EOF;
EXSR PAYSR;
IF *IN01;
WRITE TITLE;
WRITE COLHDG;
*IN01 = *OFF;
ENDIF;
WRITE EMPDETAIL;
READ ALLSHIFT;
ENDDO;
WRITE TOTALS;
EXFMT RECORD1;
*INLR = *ON;
RETURN;
BEGSR PAYSR;
SELECT;
WHEN WORKSHIFT = 'D';
HOURLYRATE = DAYRATE;
WHEN WORKSHIFT = 'A';
HOURLYRATE = AFTRATE;
WHEN WORKSHIFT = 'N';
HOURLYRATE = NIGHTRATE;
ENDSL;
SELECT;
WHEN PAYGRADE = '1';
HOURLYRATE = HOURLYRATE * 1.07;
WHEN PAYGRADE = '2';
HOURLYRATE = HOURLYRATE * 1.05;
WHEN PAYGRADE = '3';
HOURLYRATE = HOURLYRATE * 0.95;
ENDSL;
IF HRSWORKED > 40;
REGULARPAY = 40 * HOURLYRATE;
HOURSOVER = HRSWORKED - 40;
OVERPAY = HOURSOVER * HOURLYRATE * 1.5;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTOVTPAY = TOTOVTPAY + OVERPAY;
ELSE;
REGULARPAY = HRSWORKED * HOURLYRATE;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTALPAY = OVERPAY + REGULARPAY;
OVERPAY = 0;
ENDIF;
TOTEMPPAY = TOTREGPAY + TOTOVTPAY;
ENDSR;
/END-FREE
FSHIFTRATESIF E DISK RENAME(SHIFTRATES:SHIFTRATER)
FALLSHIFT IF E K DISK RENAME(ALLSHIFT:ALLSHIFTER)
FCONFIRMPAYCF E WORKSTN
FPAYRPT O E PRINTER OFLIND(*IN01)
DHOURSOVER S 3 0
/FREE
READ SHIFTRATES;
WRITE TITLE;
WRITE COLHDG;
READ ALLSHIFT;
DOW NOT %EOF;
EXSR PAYSR;
IF *IN01;
WRITE TITLE;
WRITE COLHDG;
*IN01 = *OFF;
ENDIF;
WRITE EMPDETAIL;
READ ALLSHIFT;
ENDDO;
WRITE TOTALS;
EXFMT RECORD1;
*INLR = *ON;
RETURN;
BEGSR PAYSR;
SELECT;
WHEN WORKSHIFT = 'D';
HOURLYRATE = DAYRATE;
WHEN WORKSHIFT = 'A';
HOURLYRATE = AFTRATE;
WHEN WORKSHIFT = 'N';
HOURLYRATE = NIGHTRATE;
ENDSL;
SELECT;
WHEN PAYGRADE = '1';
HOURLYRATE = HOURLYRATE * 1.07;
WHEN PAYGRADE = '2';
HOURLYRATE = HOURLYRATE * 1.05;
WHEN PAYGRADE = '3';
HOURLYRATE = HOURLYRATE * 0.95;
ENDSL;
IF HRSWORKED > 40;
REGULARPAY = 40 * HOURLYRATE;
HOURSOVER = HRSWORKED - 40;
OVERPAY = HOURSOVER * HOURLYRATE * 1.5;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTOVTPAY = TOTOVTPAY + OVERPAY;
ELSE;
REGULARPAY = HRSWORKED * HOURLYRATE;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTALPAY = OVERPAY + REGULARPAY;
OVERPAY = 0;
ENDIF;
TOTEMPPAY = TOTREGPAY + TOTOVTPAY;
ENDSR;
/END-FREE
FSHIFTRATESIF E DISK RENAME(SHIFTRATES:SHIFTRATER)
FALLSHIFT IF E K DISK RENAME(ALLSHIFT:ALLSHIFTER)
FCONFIRMPAYCF E WORKSTN
FPAYRPT O E PRINTER OFLIND(*IN01)
DHOURSOVER S 3 0
/FREE
READ SHIFTRATES;
WRITE TITLE;
WRITE COLHDG;
READ ALLSHIFT;
DOW NOT %EOF;
EXSR PAYSR;
IF *IN01;
WRITE TITLE;
WRITE COLHDG;
*IN01 = *OFF;
ENDIF;
WRITE EMPDETAIL;
READ ALLSHIFT;
ENDDO;
WRITE TOTALS;
EXFMT RECORD1;
*INLR = *ON;
RETURN;
BEGSR PAYSR;
SELECT;
WHEN WORKSHIFT = 'D';
HOURLYRATE = DAYRATE;
WHEN WORKSHIFT = 'A';
HOURLYRATE = AFTRATE;
WHEN WORKSHIFT = 'N';
HOURLYRATE = NIGHTRATE;
ENDSL;
SELECT;
WHEN PAYGRADE = '1';
HOURLYRATE = HOURLYRATE * 1.07;
WHEN PAYGRADE = '2';
HOURLYRATE = HOURLYRATE * 1.05;
WHEN PAYGRADE = '3';
HOURLYRATE = HOURLYRATE * 0.95;
ENDSL;
IF HRSWORKED > 40;
REGULARPAY = 40 * HOURLYRATE;
HOURSOVER = HRSWORKED - 40;
OVERPAY = HOURSOVER * HOURLYRATE * 1.5;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTOVTPAY = TOTOVTPAY + OVERPAY;
ELSE;
REGULARPAY = HRSWORKED * HOURLYRATE;
TOTREGPAY = TOTREGPAY + REGULARPAY;
TOTALPAY = OVERPAY + REGULARPAY;
OVERPAY = 0;
ENDIF;
TOTEMPPAY = TOTREGPAY + TOTOVTPAY;
ENDSR;
/END-FREE
RNF2120: External descriptions for file ALLSHIFT not found. file is ignored
RNF2120: External desciptions for file SHIFTRATE not found. file is ignored
The most common cause would be that those files are not on the library list when compiling.
Maybe I can help you here with a couple of RDi things that will make life easier in the long run plus help you out here.
RDI like it's predecessor WDSc has 3 modes that it can run things in. In green on black (5250) you only have two which are Batch and Interactive. RDi has Batch, Interactive, and one called Normal. Normal is where RDi will compile RPG code in.
The normal mode is very flexible and typically loads a library list from the job description that is attached to your user profile when you sign on. So if you sign on multiple boxes, you could have differing library lists depending on how you are set up. Expect inconsistency, because it is much more consistent.
Depending on what you are working on you may want to be able to have several library lists to choose from. A great way to do that is to create a library list loader program(s) to load various library lists with a single click.
To do this, create a CLLE (or CLP) source member in your development library. In the source member between the PGM and ENDPGM commands, use the change library list command (CHGLIBL) and enter in the library list that you wish to use. Have QTEMP at the top, and QGPL at the bottom (just a strong suggestion). Compile this program. For a naming convention, I use SET#XXX to let me know that these programs are library list loaders. It's your call here. Another tip, use green on black to build this CLLE program when you prompt up the CHGLIBL command, it is easier to cut and paste the libraries from an actual library list into the command. Old school but it is fast.
In RDI, in the Remote Systems Explorer you can create your own commands per system. Create a command that specifically calls your new CLLE program. Specify the library, program name, and select NORMAL as how it should run.
You can view your current library list in the Remote Systems Explorer. View it once you have signed on. Then double click on the new command you have created. Then view the library list again. It will reload with the updated library list.
Try it out. Once you get used to using the three runtime modes of RDi, there are many ways you can expand your work within this marvelous tool.
Change Library list CHGLIBL documentation:
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fcl%2Fchglibl.htm
Also, make sure that your library you are editing is inside of your EDITLIBL list. That was my issue.
Related
There is one game on the Unreal Engine 2 (pirate MMORPG with anti-cheat). I'm using reshade library to hook some functions including dinput/window input handling.
With the SendInput function i can send input but only in the active input field. F1-F12 or 1-9 keys are bind to the panel of skills. I tried to send these keys but nothing happens.
int SendKey(const wchar_t *text)
{
INPUT *keystroke;
UINT i, character_count, keystrokes_to_send, keystrokes_sent;
assert(text != NULL);
//Fill in the array of keystrokes to send.
character_count = wcslen(text);
keystrokes_to_send = character_count * 2;
keystroke = new INPUT[keystrokes_to_send];
for (i = 0; i < character_count; ++i)
{
keystroke[i * 2].type = INPUT_KEYBOARD;
keystroke[i * 2].ki.wVk = 0;
keystroke[i * 2].ki.wScan = text[i];
keystroke[i * 2].ki.dwFlags = KEYEVENTF_UNICODE;
keystroke[i * 2].ki.time = 0;
keystroke[i * 2].ki.dwExtraInfo = GetMessageExtraInfo();
keystroke[i * 2 + 1].type = INPUT_KEYBOARD;
keystroke[i * 2 + 1].ki.wVk = 0;
keystroke[i * 2 + 1].ki.wScan = text[i];
keystroke[i * 2 + 1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
keystroke[i * 2 + 1].ki.time = 0;
keystroke[i * 2 + 1].ki.dwExtraInfo = GetMessageExtraInfo();
}
//Send the keystrokes.
keystrokes_sent = SendInput((UINT)keystrokes_to_send, keystroke, sizeof(*keystroke));
delete[] keystroke;
return 0;
}
Or I can somehow use dinput to send keys?
I know that anti-cheat uses kbdHook (From Kernel-Mode) but how can he keep track of where the keys were sent in the game? (if the active input field works for me)?
PS: If I'm missing something please correct me, thanks!
I have code from a web site, and it looks like it should be simple, but too simple for SVG. How can I determine if this is truly SVG, and what it does? I am especially interested in what looks like nested & and dots[.], then split, map.
Snippet:
// the shape of the dragon, converted from a SVG image
'! ((&(&*$($,&.)/-.0,4%3"7$;(#/EAA<?:<9;;88573729/7,6(8&;'.split("").map(function(a,i) {
shape[i] = a.charCodeAt(0) - 32;
});
Full code:
//7 Dragons
//Rauri
// full source for entry into js1k dragons: http://js1k.com/2014-dragons/demo/1837
// thanks to simon for grunt help and sean for inspiration help
// js1k shim
var a = document.getElementsByTagName('canvas')[0];
var b = document.body;
var d = function(e){ return function(){ e.parentNode.removeChild(e); }; }(a);
// unprefix some popular vendor prefixed things (but stick to their original name)
var AudioContext =
window.AudioContext ||
window.webkitAudioContext;
var requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(f){ setTimeout(f, 1000/30); };
// stretch canvas to screen size (once, wont onresize!)
a.style.width = (a.width = innerWidth - 0) + 'px';
a.style.height = (a.height = innerHeight - 0) + 'px';
var c = a.getContext('2d');
// end shim
var sw = a.width,
sh = a.height,
M = Math,
Mc = M.cos,
Ms = M.sin,
ran = M.random,
pfloat = 0,
pi = M.PI,
dragons = [],
shape = [],
loop = function() {
a.width = sw; // clear screen
for ( j = 0; j < 7; j++) {
if ( !dragons[j] ) dragons[j] = dragon(j); // create dragons initially
dragons[j]();
}
pfloat++;
requestAnimationFrame(loop);
},
dragon = function(index) {
var scale = 0.1 + index * index / 49,
gx = ran() * sw / scale,
gy = sh / scale,
lim = 300, // this gets inlined, no good!
speed = 3 + ran() * 5,
direction = pi, //0, //ran() * pi * 2, //ran(0,TAU),
direction1 = direction,
spine = [];
return function() {
// check if dragon flies off screen
if (gx < -lim || gx > sw / scale + lim || gy < -lim || gy > sh / scale + lim) {
// flip them around
var dx = sw / scale / 2 - gx,
dy = sh / scale / 2 - gy;
direction = direction1 = M.atan(dx/dy) + (dy < 0 ? pi : 0);
} else {
direction1 += ran() * .1 - .05;
direction -= (direction - direction1) * .1;
}
// move the dragon forwards
gx += Ms(direction) * speed;
gy += Mc(direction) * speed;
// calculate a spine - a chain of points
// the first point in the array follows a floating position: gx,gy
// the rest of the chain of points following each other in turn
for (i=0; i < 70; i++) {
if (i) {
if (!pfloat) spine[i] = {x: gx, y: gy}
var p = spine[i - 1],
dx = spine[i].x - p.x,
dy = spine[i].y - p.y,
d = M.sqrt(dx * dx + dy * dy),
perpendicular = M.atan(dy/dx) + pi / 2 + (dx < 0 ? pi : 0);
// make each point chase the previous, but never get too close
if (d > 4) {
var mod = .5;
} else if (d > 2){
mod = (d - 2) / 4;
} else {
mod = 0;
}
spine[i].x -= dx * mod;
spine[i].y -= dy * mod;
// perpendicular is used to map the coordinates on to the spine
spine[i].px = Mc(perpendicular);
spine[i].py = Ms(perpendicular);
if (i == 20) { // average point in the middle of the wings so the wings remain symmetrical
var wingPerpendicular = perpendicular;
}
} else {
// i is 0 - first point in spine
spine[i] = {x: gx, y: gy, px: 0, py: 0};
}
}
// map the dragon to the spine
// the x co-ordinates of each point of the dragon shape are honoured
// the y co-ordinates of each point of the dragon are mapped to the spine
c.moveTo(spine[0].x,spine[0].y)
for (i=0; i < 154; i+=2) { // shape.length * 2 - it's symmetrical, so draw up one side and back down the other
if (i < 77 ) { // shape.length
// draw the one half from nose to tail
var index = i; // even index is x, odd (index + 1) is y of each coordinate
var L = 1;
} else {
// draw the other half from tail back to nose
index = 152 - i;
L = -1;
}
var x = shape[index];
var spineNode = spine[shape[index+1]]; // get the equivalent spine position from the dragon shape
if (index >= 56) { // draw tail
var wobbleIndex = 56 - index; // table wobbles more towards the end
var wobble = Ms(wobbleIndex / 3 + pfloat * 0.1) * wobbleIndex * L;
x = 20 - index / 4 + wobble;
// override the node for the correct tail position
spineNode = spine[ index * 2 - 83 ];
} else if (index > 13) { // draw "flappy wings"
// 4 is hinge point
x = 4 + (x-4) * (Ms(( -x / 2 + pfloat) / 25 * speed / 4) + 2) * 2; // feed x into sin to make wings "bend"
// override the perpindicular lines for the wings
spineNode.px = Mc(wingPerpendicular);
spineNode.py = Ms(wingPerpendicular);
}
c.lineTo(
(spineNode.x + x * L * spineNode.px) * scale,
(spineNode.y + x * L * spineNode.py) * scale
);
}
c.fill();
}
}
// the shape of the dragon, converted from a SVG image
'! ((&(&*$($,&.)/-.0,4%3"7$;(#/EAA<?:<9;;88573729/7,6(8&;'.split("").map(function(a,i) {
shape[i] = a.charCodeAt(0) - 32;
});
loop();
While the context this is used in is <canvas>, the origin may well be a SVG <polyline>.
In a first step, the letters are mapped to numbers. A bit of obscuration, but nothing too serious: get the number representing the letter and write it to an array.
const shape = [];
'! ((&(&*$($,&.)/-.0,4%3"7$;(#/EAA<?:<9;;88573729/7,6(8&;'.split("").map(function(a,i) {
shape[i] = a.charCodeAt(0) - 32;
});
results in an array
[1,0,8,8,6,8,6,10,4,8,4,12,6,14,9,15,13,14,16,12,20,5,19,2,23,4,27,8,32,15,37,33,33,28,31,26,28,25,27,27,24,24,21,23,19,23,18,25,15,23,12,22,8,24,6,27]
Now just write this array to a points attribute of a polyline, joining the numbers with a space character:
const outline = document.querySelector('#outline');
const shape = [];
'! ((&(&*$($,&.)/-.0,4%3"7$;(#/EAA<?:<9;;88573729/7,6(8&;'.split("").map(function(a,i) {
shape[i] = a.charCodeAt(0) - 32;
});
outline.setAttribute('points', shape.join(' '))
#outline {
stroke: black;
stroke-width: 0.5;
fill:none;
}
<svg viewBox="0 0 77 77" width="300" height="300">
<polyline id="outline" />
</svg>
and you get the basic outline of (half) a dragon. The rest is repetition and transformation to make things a bit more complex.
I have a question. Below is my code. I am wonder why, my output for "err3" cannot give a value of 0 ? is it because of the datatype is float?
The output are as below:
the value of err1 is -7.03125e-06
the value of err2 is 7.03125e-06
the value of err3 is -4.54747e-13
the operation between err1 and err2 is + and thus, the value for err3 should be 0.
can anyone help me to explain and solve this problem? I have google but still did not get the result.
Thanks in advance :)
void calnormal()
{
long numcal;
float indexNC0,indexNC1;
float error;
float aa0 = 0, ab0 = 0, ac0 = 0, ad0 = 0;
float bb0 = 0, bc0 = 0, bd0 = 0;
float cc0 = 0, cd0 = 0;
float dd0 = 0;
float aa, ab, ac, ad;
float bb, bc, bd;
float cc, cd;
float dd;
for(int i=0;i<noofvert;i++)
{
numcal = vlist[i].returnsizef();
for(int j=0;j<numcal;j=j+2)
{
indexNC0 = vlist[i].returnindexf(j);
u.ax = vlist[i].returnx() - vlist[indexNC0].returnx();
u.ay = vlist[i].returny() - vlist[indexNC0].returny();
u.az = vlist[i].returnz() - vlist[indexNC0].returnz();
if(j == 0){v0 = u;}
indexNC1 = vlist[i].returnindexf(j+1);
v.ax = vlist[i].returnx() - vlist[indexNC1].returnx();
v.ay = vlist[i].returny() - vlist[indexNC1].returny();
v.az = vlist[i].returnz() - vlist[indexNC1].returnz();
normal.ax = u.ay * v.az - u.az * v.ay;
normal.ay = u.az * v.ax - u.ax * v.az;
normal.az = u.ax * v.ay - u.ay * v.ax;
normal.D = - vlist[i].returnx() * normal.ax - vlist[i].returny() * normal.ay - vlist[i].returnz() * normal.az;
aa = normal.ax * normal.ax;
ab = normal.ax * normal.ay;
ac = normal.ax * normal.az;
ad = normal.ax * normal.D;
bb = normal.ay * normal.ay;
bc = normal.ay * normal.az;
bd = normal.ay * normal.D;
cc = normal.az * normal.az;
cd = normal.az * normal.D;
dd = normal.D * normal.D;
aa0 = aa0 + aa;
ab0 = ab0 + ab; bb0 = bb0 + bb;
ac0 = ac0 + ac; bc0 = bc0 + bc; cc0 = cc0 + cc;
ad0 = ad0 + ad; bd0 = bd0 + bd; cd0 = cd0 + cd; dd0 = dd0 + dd;
}
double err1,err2,err3;
**err1 = cd0 * vlist[i].returnz();
err2 = dd0 ;
err3 = err2 + err1;
cout << err1 << " " << err2 << " " << err3 << endl;**
cout << endl;
}
cout << endl;
}
err3 is very close to zero, 13 zeros. err1 and err2 have 6 zeros.
A float can store about 7 decimal digits of precision.
If you had printed out more decimals of err1 and err2 you probably see they are not exactly the same. Because err1 and err2 is float they store 7 digits of precision. They probably differ a little bit in the last digit (0.5zeros+7digits) and substracting them give a result with 0.000..00x (13 zeros).
A double have roughly a maximum of 16 decimal digits of precision. When you do computations, you lose a little precision for every operation because every result is truncated to about 16 decimal digits. If you in the end end up with 13 digits of precision it is fully normal.
While programming a game with the Tululoo Game Maker API, I am having problems with calculating collisions accurately as the x and y are being calculated from the radians.
The calculations for x and y below are producing a large number number of decimal points which I am finding difficult to check for collisions.
image_angle is the final angle of the pistol in degrees that the bullet uses initially.
In Setup:
x = instance_list(pistol)[0].x;
y = instance_list(pistol)[0].y;
startAng = instance_list(pistol)[0].image_angle;
this.travelX = cos(degtorad(instance_list(pistol)[0].image_angle)) * 5;
this.travelY = sin(degtorad(instance_list(pistol)[0].image_angle)) * 5;
In Update Frame:
x+=this.travelX;
y+=this.travelY;
Calculating the Angle that the ball will bounce off a wall at, messy I know:
for(var i = 0; i < instance_number(bounce_barrier);i++){
if(place_meeting(x,y,instance_list(bounce_barrier)[i])){
if(Math.round(x*10)/10 > instance_list(bounce_barrier)[i].x ){
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(y > instance_list(bounce_barrier)[i].y - 5 && y <= instance_list(bounce_barrier)[i].y + 10){
newAng = 180 - startAng;
this.travelX = -cos(degtorad(newAng)) * 15;
this.travelY = -sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(y <= instance_list(bounce_barrier)[i].y - 5 + bounce_spr.height && y >= instance_list(bounce_barrier)[i].y + bounce_spr.height - 10){
newAng = 180 - startAng;
this.travelX = -cos(degtorad(newAng)) * 15;
this.travelY = -sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else if(x < instance_list(bounce_barrier)[i].x){
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
else{}
}
}
place_meeting is Part of the Tululoo Game API:
function __place_meeting__(nx, ny, what, many) {
this.other = null;
var i, l,
// sprite, scale:
ts = this.sprite_index,
tsx, tsy, tfx, tfy, tst,
// circle:
tcx, tcy, tcr,
// bbox:
tbl, tbr, tbt, tbb,
// instances, multiple, output, types:
tz, tm, ct, ch, ra,
// other:
o, ox, oy, os, ost, osx, osy, ofx, ofy, ofr;
if (ts == null) return false;
tfx = ts.xoffset;
tfy = ts.yoffset;
tsx = this.image_xscale;
tsy = this.image_yscale;
tst = ts.collision_shape;
// bbox:
if (tst == 2) {
tbl = nx + tsx * (ts.collision_left - tfx);
tbr = nx + tsx * (ts.collision_right - tfx);
tbt = ny + tsy * (ts.collision_top - tfy);
tbb = ny + tsy * (ts.collision_bottom - tfy);
}
// circle:
if (tst == 3) {
tcr = ts.collision_radius * (tsx > tsy ? tsx : tsy);
tcx = nx + tsx * (ts.width / 2 - tfx);
tcy = ny + tsy * (ts.height / 2 - tfy);
}
//
tz = (what.__instance ? [what] : instance_list(what));
tm = many ? true : false;
if (tm) ra = [];
l = tz.length;
for (i = 0; i < l; i++) {
o = tz[i];
if (!o.collision_checking) continue;
os = o.sprite_index;
if (os == null) continue;
ox = o.x; osx = o.image_xscale;
oy = o.y; osy = o.image_yscale;
ost = os.collision_shape;
ct = (tst << 4) | ost;
ch = false;
switch(ct) {
case 0x22:
if (osx == 1 && osy == 1) {
ofx = os.xoffset; ofy = os.yoffset;
if (!collide_bbox_bbox(tbl, tbt, tbr, tbb,
ox + os.collision_left - ofx, oy + os.collision_top - ofy,
ox + os.collision_right - ofx, oy + os.collision_bottom - ofy)) break;
} else if (!collide_bbox_sbox(tbl, tbt, tbr, tbb, ox, oy, osx, osy, os)) break;
ch = true;
break;
case 0x23:
ofr = os.collision_radius * (osx > osy ? osx : osy);
ofx = ox + osx * (os.width / 2 - os.xoffset);
ofy = oy + osy * (os.height / 2 - os.yoffset);
if (!collide_bbox_circle(tbl, tbt, tbr, tbb, ofx, ofy, ofr)) break;
ch = true;
break;
case 0x32:
if (osx == 1 && osy == 1) {
ofx = os.xoffset; ofy = os.yoffset;
if (!collide_bbox_circle(
ox + os.collision_left - ofx, oy + os.collision_top - ofy,
ox + os.collision_right - ofx, oy + os.collision_bottom - ofy,
tcx, tcy, tcr)) break;
} else if (!collide_sbox_circle(ox, oy, osx, osy, os, tcx, tcy, tcr)) break;
ch = true;
break;
case 0x33:
ofr = os.collision_radius * (osx > osy ? osx : osy);
ofx = ox + osx * (os.width / 2 - os.xoffset);
ofy = oy + osy * (os.height / 2 - os.yoffset);
if (!collide_circle_circle(tcx, tcy, tcr, ofx, ofy, ofr)) break;
ch = true;
break;
} if (!ch) continue;
this.other = o;
o.other = this;
if (!tm) return (o);
ra.push(o);
} return ra;
}
I have managed to make a bullet bounce off a wall at an angle proportional to where it has been shot from, but the collision detection is very bad as it bounces some bullets but not all, some just go straight through the wall.
Just added the Line Collision Detection, ive made the bullets lines so I can see the
this.oldTravelX,this.oldTravelY to this.travelX,this.travelY. It has definitely improved but some of the bullets are still going through.
Some bullets seem to stick inside the bouncing block or slide down the left side of the bouncing block then decide whether to go left or right.
Updated Code:
pntdis = point_distance(this.oldTravelX, this.oldTravelY, this.travelX, this.travelY);
noPoints = pntdis/0.01;
for(var i=0; i < pntdis; i+=noPoints)
{
pointsArrX[i] = this.travelX - (this.oldTravelX * i);
pointsArrY[i] = this.travelY - (this.oldTravelY * i);
}
for(var i=0;i<pointsArrX.length;i++){
if(place_meeting(Math.round(pointsArrX[i]),Math.round(pointsArrY[i]),bounce_barrier) || place_meeting(x,y,bounce_barrier))
{
newAng = 180 - startAng;
this.travelX = +cos(degtorad(newAng)) * 15;
this.travelY = +sin(degtorad(newAng)) * 15;
startAng = newAng;
}
}
Thanks in advance.
It looks like the place_meeting function is supposed to determine whether there's a collision between the bullet and the barrier. However, this function only takes the new position of the bullet. Given the bullet moves 5 units per update, it's possible that the bullet could move from one side of the barrier to the other in a single frame. e.g.:
|
. |
\| barrier
\
|\_______
\
.
place_meeting should take both the old and new positions of the bullet so that it can determine whether any intermediate position collided with the barrier (e.g. by doing line-line intersection testing with the path of the bullet and the edges of the barrier; it should probably also return the collision point).
EDIT
Your updated code looks like it's intended to check for collision of a number of points along the path of the bullet. There are faster ways to do this, but your method may be fast enough, and is easy to understand. There appears to be a bug in how you calculate the points to check though.
Stepping through the code manually on paper:
pntdis = 5 // assume point_distance returns 5
noPoints = 5 / 0.01 = 500
i = 0
pointsArrX[0] = this.travelX
pointsArrY[0] = this.travelY
i = i + noPoints = 500
500 < 5: false, for loop ends
Other things to consider:
You might want a break statement after you've detected a collision so you don't keep testing further points.
You could combine the two for loops into one because you're not reusing the values in the array. Just calculate your test point and then test it immediately.
Try using console.log to output debugging information as your program runs so you can get a better idea of what's happening.
Use var before your variables (such as pntdis and noPoints) to avoid accidentally creating global variables.
Does Lua make use of 64-bit integers? How do I use it?
Compile it yourself. Lua uses double-precision floating point numbers by default. However, this can be changed in the source (luaconf.h, look for LUA_NUMBER).
require "bit"
-- Lua unsigned 64bit emulated bitwises
-- Slow. But it works.
function i64(v)
local o = {}; o.l = v; o.h = 0; return o;
end -- constructor +assign 32-bit value
function i64_ax(h,l)
local o = {}; o.l = l; o.h = h; return o;
end -- +assign 64-bit v.as 2 regs
function i64u(x)
return ( ( (bit.rshift(x,1) * 2) + bit.band(x,1) ) % (0xFFFFFFFF+1));
end -- keeps [1+0..0xFFFFFFFFF]
function i64_clone(x)
local o = {}; o.l = x.l; o.h = x.h; return o;
end -- +assign regs
-- Type conversions
function i64_toInt(a)
return (a.l + (a.h * (0xFFFFFFFF+1)));
end -- value=2^53 or even less, so better use a.l value
function i64_toString(a)
local s1=string.format("%x",a.l);
local s2=string.format("%x",a.h);
local s3="0000000000000000";
s3=string.sub(s3,1,16-string.len(s1))..s1;
s3=string.sub(s3,1,8-string.len(s2))..s2..string.sub(s3,9);
return "0x"..string.upper(s3);
end
-- Bitwise operators (the main functionality)
function i64_and(a,b)
local o = {}; o.l = i64u( bit.band(a.l, b.l) ); o.h = i64u( bit.band(a.h, b.h) ); return o;
end
function i64_or(a,b)
local o = {}; o.l = i64u( bit.bor(a.l, b.l) ); o.h = i64u( bit.bor(a.h, b.h) ); return o;
end
function i64_xor(a,b)
local o = {}; o.l = i64u( bit.bxor(a.l, b.l) ); o.h = i64u( bit.bxor(a.h, b.h) ); return o;
end
function i64_not(a)
local o = {}; o.l = i64u( bit.bnot(a.l) ); o.h = i64u( bit.bnot(a.h) ); return o;
end
function i64_neg(a)
return i64_add( i64_not(a), i64(1) );
end -- negative is inverted and incremented by +1
-- Simple Math-functions
-- just to add, not rounded for overflows
function i64_add(a,b)
local o = {};
o.l = a.l + b.l;
local r = o.l - 0xFFFFFFFF;
o.h = a.h + b.h;
if( r>0 ) then
o.h = o.h + 1;
o.l = r-1;
end
return o;
end
-- verify a>=b before usage
function i64_sub(a,b)
local o = {}
o.l = a.l - b.l;
o.h = a.h - b.h;
if( o.l<0 ) then
o.h = o.h - 1;
o.l = o.l + 0xFFFFFFFF+1;
end
return o;
end
-- x n-times
function i64_by(a,n)
local o = {};
o.l = a.l;
o.h = a.h;
for i=2, n, 1 do
o = i64_add(o,a);
end
return o;
end
-- no divisions
-- Bit-shifting
function i64_lshift(a,n)
local o = {};
if(n==0) then
o.l=a.l; o.h=a.h;
else
if(n<32) then
o.l= i64u( bit.lshift( a.l, n) ); o.h=i64u( bit.lshift( a.h, n) )+ bit.rshift(a.l, (32-n));
else
o.l=0; o.h=i64u( bit.lshift( a.l, (n-32)));
end
end
return o;
end
function i64_rshift(a,n)
local o = {};
if(n==0) then
o.l=a.l; o.h=a.h;
else
if(n<32) then
o.l= bit.rshift(a.l, n)+i64u( bit.lshift(a.h, (32-n))); o.h=bit.rshift(a.h, n);
else
o.l=bit.rshift(a.h, (n-32)); o.h=0;
end
end
return o;
end
-- Comparisons
function i64_eq(a,b)
return ((a.h == b.h) and (a.l == b.l));
end
function i64_ne(a,b)
return ((a.h ~= b.h) or (a.l ~= b.l));
end
function i64_gt(a,b)
return ((a.h > b.h) or ((a.h == b.h) and (a.l > b.l)));
end
function i64_ge(a,b)
return ((a.h > b.h) or ((a.h == b.h) and (a.l >= b.l)));
end
function i64_lt(a,b)
return ((a.h < b.h) or ((a.h == b.h) and (a.l < b.l)));
end
function i64_le(a,b)
return ((a.h < b.h) or ((a.h == b.h) and (a.l <= b.l)));
end
-- samples
a = i64(1); -- 1
b = i64_ax(0x1,0); -- 4294967296 = 2^32
a = i64_lshift(a,32); -- now i64_eq(a,b)==true
print( i64_toInt(b)+1 ); -- 4294967297
X = i64_ax(0x00FFF0FF, 0xFFF0FFFF);
Y = i64_ax(0x00000FF0, 0xFF0000FF);
-- swap algorithm
X = i64_xor(X,Y);
Y = i64_xor(X,Y);
X = i64_xor(X,Y);
print( "X="..i64_toString(X) ); -- 0x00000FF0FF0000FF
print( "Y="..i64_toString(Y) ); -- 0x00FFF0FFFFF0FFFF
Lua 5.3 introduces the integer subtype, which uses 64-bit integer by default.
From Lua 5.3 reference manual
The type number uses two internal representations, one called integer and the other called float. Lua has explicit rules about when each representation is used, but it also converts between them automatically as needed (see ยง3.4.3). Therefore, the programmer may choose to mostly ignore the difference between integers and floats or to assume complete control over the representation of each number. Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats. The option with 32 bits for both integers and floats is particularly attractive for small machines and embedded systems. (See macro LUA_32BITS in file luaconf.h.)