Page 1 of 1

Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 1:19 am
by bamby1983
The purpose of this thread is to provide the Game Editor community with easy-to-use reusable functions to speed up game development. Most of these functions would need no customization and can simply be used "out-of-the-box" once the code for them has been copy-pasted into the global code.

I will keep updating new functions and their corresponding code on this thread. Each will likely be a separate response to this thread, so I'll try and maintain an index in this original post linking to each of the functions I share.


Links to Posts Regarding Reusable Functions and their Code:

Mouse Look: Look around the game world using just your mouse (as is done in first person shooter games)

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 1:30 am
by bamby1983
CUSTOM FUNCTION: Requires no editing or customization

Mouse Look: Look around the game world using just your mouse (as is done in first person shooter games). This works for 2D as well as simulated 3D GE games.


Features:
1) Look around the screen (auto scroll) horizontally and vertically using just the mouse cursor
2) Locks the crosshairs at the center of the screen (the crosshairs are an actor - the mouse cursor is to be hidden as explained below)
3) The scroll speed is controlled by the speed with which the mouse is moved
4) Allows the user to continue scrolling even after the mouse cursor hits the edge of the screen. However, at this point, the scroll speed will be equal to the mouse scroll speed immediately before the cursor hit the edge of the screen.
5) Prevents the view actor from moving outside the background image area while scrolling in 2D games. This is managed dynamically by the program and automatically adjusts according to the image and view size
6) In simulated 3D games, when the view reaches the edge of the screen, it continues moving from the opposite side of the screen to provide an illusion of a seamless, 3D environment. This requires the background image to have contain the exact same view at the far left and right of the image. The same holds true for the top and bottom. This is done dynamically as well, although it is currently limited to a resolution of 1360 X 768
7) Although not included in the game code posted in this thread, the attached demo contains a feature that actively displays the X and Y mouse scroll speed in real time.


Requirements:
To enable mouse look, you will need:
1) An actor for the crosshairs
2) An actor for the background
3) To copy the function code into the Global Code and save it
4) To hide the mouse cursor (recommended), go to Config -> Game Properties, then click the drop down menu in the screenshot below and select "Hide Mouse"
Image
5) If this is going to be used for a simulated 3D game, the background image will need to be set up so that the edges of the screen corresponding to the view size are identical. Additional efforts may be needed to make actors at the edge of the screen seem consistent (this does not include the Background, view and Crosshair actors).


Using this Function:
To use mouse look, simply paste the following function in your "view" actor's "Draw" event and replace the function parameters to match your game actors. These are explained immediately below the code.

Code: Select all
mouseLook("Background", "Crosshairs", "3D");


"Background" - This is the name of the actor that displays the background image of your game
"Crosshairs" - This is the name of the actor that displays the crosshairs at the center of the screen
"3D" - This denotes whether the game is a 2D game or a simulated 3D game. Enter "2D" for a 2D game and "3D" for a 3D game. The quotes are necessary.


Function Code: Copy the following code into the Global Code and save it there.
Code: Select all
int xmouse_prev=xmouse;
int ymouse_prev=ymouse;
int xscroll_speed=0;
int yscroll_speed=0;

void mouseLook(char actor_background[30], char actor_crosshairs[30], char game_dimensions[4]) {
    if(xmouse!=xmouse_prev) { // If the horizontal mouse position has changed
        view.x+=(xmouse-xmouse_prev); // Moving the view along with the mouse
        getclone(actor_crosshairs)->x+=(xmouse-xmouse_prev); // Moving the crosshairs along with the view
        xscroll_speed=abs(xmouse_prev-xmouse);
        xmouse_prev=xmouse; // Setting value of xmouse_prev to xmouse for the next frame
                            }
    else if (xmouse<=20) { // If the mouse is at the extreme left of the screen
        view.x-=xscroll_speed; // Moving the view to the left
        getclone(actor_crosshairs)->x-=xscroll_speed; // Moving the crosshairs to the left
                         }
    else if (xmouse>=view.width-40) { // If the mouse is at the extreme right of the screen
        view.x+=xscroll_speed; // Moving the view to the left
        getclone(actor_crosshairs)->x+=xscroll_speed; // Moving the crosshairs to the right
                                    }


    if (strcmp(game_dimensions,"2D")==0&&view.x<=getclone(actor_background)->x-(getclone(actor_background)->width/2)) // If the game mode is 2D and view is at the left of the background image
        view.x=getclone(actor_background)->x-(getclone(actor_background)->width/2); // Stop moving left
    else if (strcmp(game_dimensions,"3D")==0&&view.x<=getclone(actor_background)->x-(getclone(actor_background)->width/2)+(1360-view.width)+xscroll_speed) // If the game mode is 3D and view is at the left of the background image
        // Jump to the right of the screen minus the xscroll_speed (that is the distance the screen would move in 1 frame)
        view.x=getclone(actor_background)->x+(getclone(actor_background)->width/2)-view.width-xscroll_speed-(1360-view.width)+10;
    else if (strcmp(game_dimensions,"2D")==0&&view.x+view.width>=getclone(actor_background)->x+(getclone(actor_background)->width/2)) // If the view is at the right of the background image
        view.x=getclone(actor_background)->x+(getclone(actor_background)->width/2)-view.width;  // Stop moving right
    else if (strcmp(game_dimensions,"3D")==0&&view.x+view.width>=getclone(actor_background)->x+(getclone(actor_background)->width/2)-(1360-view.width)-xscroll_speed) // If the game mode is 3D and view is at the right of the background image
        // Jump to the left of the screen plus the xscroll_speed (that is the distance the screen would move in 1 frame)
        view.x=getclone(actor_background)->x-(getclone(actor_background)->width/2)+xscroll_speed+(1360-view.width)-10;
 
    getclone(actor_crosshairs)->x=view.x+(view.width/2);


    if (strcmp(game_dimensions,"2D")==0&&view.x<=getclone(actor_background)->x-(getclone(actor_background)->width/2)) // If the game mode is 2D and view is at the left of the background image
        view.x=getclone(actor_background)->x-(getclone(actor_background)->width/2); // Stop moving right
    else if (strcmp(game_dimensions,"3D")==0&&view.x<=getclone(actor_background)->x-(getclone(actor_background)->width/2)+(768-view.width)) // If the game mode is 3D and view is at the left edge of the background image
        // Jump to the right of the screen minus the xscroll_speed (that is the distance the screen would move in 1 frame)
        view.x=getclone(actor_background)->x+(getclone(actor_background)->width/2)-view.width-xscroll_speed-(768-view.width)-10;
    else if (strcmp(game_dimensions,"2D")==0&&view.x+view.width>=getclone(actor_background)->x+(getclone(actor_background)->width/2)) // If the view is at the right edge of the background image
        view.x=getclone(actor_background)->x+(getclone(actor_background)->width/2)-view.width;  // Stop moving left
    else if (strcmp(game_dimensions,"3D")==0&&view.x+view.width>=getclone(actor_background)->x+(getclone(actor_background)->width/2)-(768-view.width)) // If the game mode is 3D and the view is at the right edge of the background image
        // Jump to the left of the screen plus the xscroll_speed (that is the distance the screen would move in 1 frame)
        view.x=getclone(actor_background)->x-(getclone(actor_background)->width/2)+xscroll_speed+(768-view.width)+10;
 
    getclone(actor_crosshairs)->x=view.x+(view.width/2);



    if(ymouse!=ymouse_prev) { // If the vertical mouse position has changed
        view.y+=(ymouse-ymouse_prev); // Moving the view along with the mouse
        getclone(actor_crosshairs)->y+=(ymouse-ymouse_prev); // Moving the crosshairs along with the view
        yscroll_speed=abs(ymouse_prev-ymouse);
        ymouse_prev=ymouse; // Setting value of ymouse_prev to ymouse for the next frame
                            }
    else if (ymouse<=20) { // If the mouse is at the top edge of the screen
        view.y-=yscroll_speed; // Moving the view up
        getclone(actor_crosshairs)->y-=yscroll_speed; // Moving the crosshairs up
                         }
    else if (ymouse>=view.height-40) { // If the mouse is at the bottom edge of the screen
        view.y+=yscroll_speed; // Moving the view down
        getclone(actor_crosshairs)->y+=yscroll_speed; // Moving the crosshairs down
                                    }
    if (strcmp(game_dimensions,"2D")==0&&view.y<=getclone(actor_background)->y-(getclone(actor_background)->height/2)) // If the game mode is 2D and view is at the top of the background image
        view.y=getclone(actor_background)->y-(getclone(actor_background)->height/2); // Stop moving up
    else if (strcmp(game_dimensions,"3D")==0&&view.y<=getclone(actor_background)->y-(getclone(actor_background)->height/2)+(768-view.height)) // If the game mode is 3D and view is at the top of the background image
        // Jump to the bottom of the screen minus the yscroll_speed (that is the distance the screen would move in 1 frame)
        view.y=getclone(actor_background)->y+(getclone(actor_background)->height/2)-view.height-yscroll_speed-(768-view.height)-10;
    else if (strcmp(game_dimensions,"2D")==0&&view.y+view.height>=getclone(actor_background)->y+(getclone(actor_background)->height/2)) // If the view is at the bottom of the background image
        view.y=getclone(actor_background)->y+(getclone(actor_background)->height/2)-view.height;  // Stop moving down
    else if (strcmp(game_dimensions,"3D")==0&&view.y+view.height>=getclone(actor_background)->y+(getclone(actor_background)->height/2)-(768-view.height)) // If the game mode is 3D and the view is at the bottom of the background image
        // Jump to the top of the screen plus the yscroll_speed (that is the distance the screen would move in 1 frame)
        view.y=getclone(actor_background)->y-(getclone(actor_background)->height/2)+yscroll_speed+(768-view.height)+10;
 
    getclone(actor_crosshairs)->y=view.y+(view.height/2);
                                                   }



Additional Options:
To begin the game with the screen centered in the original view position, paste the following code into the "view" actor's "Create" event. This is to avoid scrolling or an unexpected screen starting position when your game launches.
Code: Select all
// Initializing mouse position in variables
xmouse_prev=xmouse;
ymouse_prev=ymouse;



Example GED File: Attached - A sample simulated 3D game environment. The world map continues scrolling as though the player is moving "around" the screen.

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 12:04 pm
by lcl
That mouse look function is really nice for 2D games!

Hey here's a way to improve it. :)
If you multiply the view moving values with the factor of (background.width / view.width) you can make it so that the
else if statements are not needed and the game is still able to scroll through the whole width of the background image.

See the old and new code compared.

Your code:
Code: Select all
if(xmouse!=xmouse_prev) { // If the horizontal mouse position has changed
    view.x+=(xmouse-xmouse_prev); // Moving the view along with the mouse
    Crosshairs.x+=(xmouse-xmouse_prev); // Moving the crosshairs along with the view
    xmouse_prev=xmouse; // Setting value of xmouse_prev to xmouse for the next frame
                        }
else if (xmouse<=20) { // If the mouse is at the extreme left of the screen
    view.x-=10; // Moving the view to the left
    Crosshairs.x-=10; // Moving the crosshairs to the left
                    }
else if (xmouse>=view.width-40) { // If the mouse is at the extreme left of the screen
    view.x+=10; // Moving the view to the left
    Crosshairs.x+=10; // Moving the crosshairs to the left
                                }

My version of it:
Code: Select all
if(xmouse!=xmouse_prev) { // If the horizontal mouse position has changed
    view.x+=(xmouse-xmouse_prev)*(Background.width/view.width); // Moving the view along with the mouse
    Crosshairs.x+=(xmouse-xmouse_prev)*(Background.width/view.width); // Moving the crosshairs along with the view
    xmouse_prev=xmouse; // Setting value of xmouse_prev to xmouse for the next frame
                        }

Try replacing my code over yours and you'll see how it works. I hope this was helpful! :)
(I also suggest you to put up a demo with the function used instead of the code in view's draw actor event. Would look prettier. :) )

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 8:47 pm
by bamby1983
That's a pretty neat way of maintaining a reasonable scroll speed based on the world:view size ratio. I'm not sure whether it would work at the edge of the screen, though. My code calculates the movement speed based on the mouse position relative to the previous frame. If the mouse reaches the edge of the screen and stays there, the relative motion would be zero, so there would be no motion. The background and view size are constants and act as a pretty neat multiplying factor, but initial part of the equation would be zero. :(

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 8:54 pm
by lcl
Did you try it? For me it worked just fine.

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sat Mar 23, 2013 9:29 pm
by bamby1983
lcl wrote:Did you try it? For me it worked just fine.

It worked wonderfully for 2D - MUCH better than the code I wrote. It even allowed me to vary the scrolling speed after the cursor hit the edge of the screen! It didn't work for 3D, though.

I'm curious as to how this code works.

Code: Select all
if(xmouse!=xmouse_prev) { // If the horizontal mouse position has changed
    view.x+=(xmouse-xmouse_prev)*(Background.width/view.width); // Moving the view along with the mouse
    Crosshairs.x+=(xmouse-xmouse_prev)*(Background.width/view.width); // Moving the crosshairs along with the view
    xmouse_prev=xmouse; // Setting value of xmouse_prev to xmouse for the next frame
                        }


If the cursor is at the edge of the screen, then xmouse should equal to xmouse_prev, so the value of view.x+=...... should equal to 0. How is this not happening and how does the ratio of the background and view width influence this outcome?

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sun Mar 24, 2013 5:12 am
by GEuser
Thanks bamby. Looking forward to seeing what you put up.

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sun Mar 24, 2013 7:38 pm
by lcl
bamby1983 wrote:It even allowed me to vary the scrolling speed after the cursor hit the edge of the screen!

No it didn't. :D The trick is here: the value the view has to be moved is calculated in a way that the view will reach its
max position at the same time when the mouse reaches the edge of the window. :)

For that, I added the *(Backgound.width/view.width) part to the code.
The result of the fraction is the amount of pixels the view has to move when the mouse moves 1 pixel.

By multiplying the mouse x axis movement with this value and then moving the view by the result, it is possible
the see the whole 2D background image just by moving mouse form one edge of the screen to the other one. :)

bamby1983 wrote:If the cursor is at the edge of the screen, then xmouse should equal to xmouse_prev, so the value of view.x+=...... should equal to 0.

And it is equal to 0. And that is what we want, because with my code, the edge of the background has been reached as the mouse has reached the edge of the view. :)

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sun Mar 24, 2013 8:32 pm
by bamby1983
I think I understand. The view.x calculated is 0 with respect to the screen/mouse co-ordinates and not with respect to the game center! I thought assigning view.x to a value of zero would mean that it was zero with respect to the game center. I didn't realize that GE automatically converts screen co-ordinates to game center co-ordinates automatically like that (isn't that what's happening here)?

Also, I did a little experiment and realized that the mouse never reaches the end of the screen until the background image has also ended. That removes the necessity for scroll control at the edges! This is probably because of the width ratio you coded in. However, what this means is that the scroll speed will vary depending on the background size. We can work around that by ensuring that all background are the same size as the largest one so that the scroll speed is constant throughout the game. There would be additional coding required to make the view jump to the other side in a simulated 3D game if the view size is smaller. This can be done dynamically to make it a reusable function.

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Sun Mar 24, 2013 8:55 pm
by lcl
bamby1983 wrote:I think I understand. The view.x calculated is 0 with respect to the screen/mouse co-ordinates and not with respect to the game center! I thought assigning view.x to a value of zero would mean that it was zero with respect to the game center. I didn't realize that GE automatically converts screen co-ordinates to game center co-ordinates automatically like that (isn't that what's happening here)?

Nope. Notice that it is view.x += .... not view.x = ...
When the ... part is 0, view.x is not being set to 0, instead view.x is being increased by 0, so it's just staying where it is. :)

bamby1983 wrote:Also, I did a little experiment and realized that the mouse never reaches the end of the screen until the background image has also ended. That removes the necessity for scroll control at the edges! This is probably because of the width ratio you coded in.

That was the reason I added that multiplying by the width ratio. As I said:
me wrote:The trick is here: the value the view has to be moved is calculated in a way that the view will reach its
max position at the same time when the mouse reaches the edge of the window.
:)

bamby1983 wrote:However, what this means is that the scroll speed will vary depending on the background size.

Yes it does, I know. But I think it's still better than making the view move with some predefined constant speed when the mouse has reached the edges of the screen. :wink:

bamby1983 wrote:There would be additional coding required to make the view jump to the other side in a simulated 3D game if the view size is smaller. This can be done dynamically to make it a reusable function.

How would you do this? The mouse would still be in the edge of the screen and thus not able to move to that direction, so after turning one whole revolution, the rotating would act differently (if one doesn't change the direction of rotating, in which case the mouse would have some space to move to again).

Re: Custom Functions for GE: Easy-to-Use Resuable Code

PostPosted: Mon Mar 25, 2013 12:02 am
by bamby1983
You're right, I didn't think of that. Changing the direction may not help coz the player would still be trying to move his mouse in the same position, which is at the edge. :(