Monster/NPC collisions

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

Post Reply
Bluefeather42
Slime Knight
Posts: 115
Joined: Fri Jan 13, 2023 1:13 am

Monster/NPC collisions

Post by Bluefeather42 »

Once again, I am stuck. What's the best way to handle projectile collisions if you have more than one type of enemy? Most of the freely available scripts I've seen assign a hitbox to each enemy but only have one type of enemy. Charbile's Hatful Adventure uses slicecollide, NPC refs and global IDs to see which enemy was hit, which I understand, but seems slightly more convoluted.

EDIT: I should add, since my game is based on sniping monsters, I'm not convinced I actually need more than one monster on the map at once, if that makes a difference.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7741
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Re: Monster/NPC collisions

Post by Bob the Hamster »

It might help to share some of your current projectile collision script.

It sounds like you already have something that works for a single enemy type, and want to extend it without overcomplicating it
Bluefeather42
Slime Knight
Posts: 115
Joined: Fri Jan 13, 2023 1:13 am

Re: Monster/NPC collisions

Post by Bluefeather42 »

I've been away from this project for a couple months, so I threw in some of the code from CHA to try out. It technically works. The arrow hits the monster, both the arrow and the monster are deleted, but I get a script error since projectileeachtick is still trying to run. I'm guessing I'll have to change the projectile code a little more or I've got some dumb error I've missed.

Code: Select all

define constant(12345, sli:dataslice)
include,globvar.hss
include,util.hss



################################################################################
# Projectiles - From the OHRRPGCE wiki.  Modified by removing the "arc" functionality.  
# Start a new projectile on an arcing path.
# Speed is the ground speed in pixels per tick.
# x distance and y distance is how far you want to shoot the projectile, relative
# to the initial position (like "move slice by").
# z distance is used when shooting at a target with a different height, e.g. aiming
# at the top of a tree or up a cliff. Positive z distance means shooting upwards

script, fire projectile, slice, speed, x distance, y distance, begin
    variable(dist, time)

    dist := sqrt(xdistance ^ 2 + ydistance ^ 2)

    # Calculate time-in-air, in ticks
    time := (dist + speed / 2) / speed
    if (time <= 0) then (time := 1)

    # Save some other necessary data
    prj:x100 := slicex(slice) * 100
    prj:y100 := slicey(slice) * 100
    prj:v_x100 := xdistance * 100 / time
    prj:v_y100 := ydistance * 100 / time
    prj:time := time
    save projectile data(create data slice(slice))
end

# Update the position of a projectile slice. Needs to be called every tick.
# Returns true if still in flight, or false if the projectile has reached the end.
script, projectile eachtick, slice, begin
    variable(dataslice, hit)
    dataslice := lookup slice(sli:dataslice, slice)
    if (dataslice == false) then (script error($99="Couldn't find projectile data slice"))

    load projectile data(dataslice)
    if (prj:time <= 0) then (exit returning(false))  # Already finished
    prj:time -= 1
    prj:x100 += prj:v_x100
    prj:y100 += prj:v_y100
    
    save projectile data(dataslice)

    # Add 50 to round to nearest pixel
    put slice(slice, (prj:x100 + 50) / 100, (prj:y100 + 50) / 100)
    return (prj:time > 0)
    
    variable(j)
    for(j, 0, findCollidingSlice(lookupSlice(sl:walkaboutLayer), slice, getCount, false, true)--1) do(
        hit := findCollidingSlice(lookupSlice(sl:walkaboutLayer), slice, j, false, true)
        if(npcReferenceFromSlice(hit) && getNPCPool(npcReferenceFromSlice(hit)) == pool:global) then(
        # Damage enemy/npc
            damagecritter(npcReferenceFromSlice(hit))
            freeSlice(slice)
            exitScript()
        )
    )
end


# Set this to the correct map layer, above the hero
define constant(sl:map layer4, projectile layer)

define constant(80, arrow distance)

script, vecX, dir, dist, begin
    switch (dir) do (
        case (up, down) do (return (0))
        case (right) do (return (dist))
        case (left) do (return (-1 * dist))
    )
end

script, vecY, dir, dist, begin
    switch (dir) do (
        case (left, right) do (return (0))
        case (down) do (return (dist))
        case (up) do (return (-1 * dist))
    )
end


################################################################################
# Here is one way to run the scripts above: by using a timer.
# Each projectile in the air will need a different timer and a different global variable.

defineconstant(1000, sli:projectile)
defineconstant(15, timer:arrow1)
globalvariable(1, arrow1)
globalvariable(2, canshoot)

script, fire arrow1, begin
	set timer(4, 1, 8, set hero picture (0, 0))
	arrow1 := load walkabout sprite(2)
	setparent(arrow1, lookupslice(projectile layer))
	put slice(arrow1, heropixelx, heropixely)
	if (hero direction(0) == 0) then (
		set sprite frame(arrow1, 1)
	) else if (hero direction(0) == 1) then (
		set sprite frame(arrow1, 3)
	) else if (hero direction(0) == 2) then (
		set sprite frame(arrow1, 5)
	) else (
		set sprite frame(arrow1, 7)
	)
	variable(x, y)
	x := vecX(herodirection, arrow distance)  # Find the position 60 pixels ahead of the player
	y := vecY(herodirection, arrow distance)
	set timer(2, 0, 1, fire projectile(arrow1, 8, x, y))  # 8 pixel/tick, timer added by me 
	set timer(timer:arrow1, 0, 1, @arrow1 eachtick)
	stealth -= 10 
	

end

script, arrow1 eachtick, timer id, begin
	if (projectile eachtick(arrow1)) then (
	## Still in the air, run timer again
	set timer(timer id, 0)  # Restarts the timer with a count of 0 (next tick)
	) else (
		set timer(timer:arrow1, 0, 2, freeslice(arrow1))
		canshoot := true
	)


end 

...

script, damagecritter, ref, begin
	# add more stuff later, this is just for testing purposes now
	destroy NPC(ref)
	exit script()
end
Bluefeather42
Slime Knight
Posts: 115
Joined: Fri Jan 13, 2023 1:13 am

Re: Monster/NPC collisions

Post by Bluefeather42 »

After having thought about it for a while I am definitely going to have only a single monster on the map at a time, so I'll probably just make a single hitbox for projectiles to collide with and use slice extras for the stats.
Post Reply